#!/usr/bin/env python
# coding:utf-8
#python version: 2.7
__author__ = 'pa769@qq.com'

import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
import scipy.stats as scs
from scipy.stats import binom
import matplotlib.mlab as mlab

'''
构造器，计时用
'''


def GetRunTime(func):
    def check(*args, **args2):
        startTime = datetime.datetime.now()
        f = func(*args, **args2)
        endTime = datetime.datetime.now()
        print((endTime - startTime))
        return f

    return check


def create_price(u, v, n=1000000):  # 价格样本集合
    return pd.DataFrame({'price': np.random.normal(u, v, n), 'key': [0] * n})


def create_pid(u, v, n=100000):  # 投资平台样本集合
    return pd.DataFrame({'pid': np.random.normal(u, v, n), 'key': [0] * n})


def create_timelen():  # 目标资产期限
    return pd.DataFrame({'TimeLen': [30, 60, 90], 'key': [0] * 3})


def get_df_all():
    '''
    获得模拟投资记录
    '''
    df_price = create_price(u1, v1).sample(1000)
    df_timelen = create_timelen()
    df_pid = create_pid(u2, v2).sample(1000)
    df_pid['pid'] = df_pid.pid.map(int)
    df = pd.merge(df_price, df_pid)
    df = pd.merge(df, df_timelen).iloc[:, 1:4]
    # 抽样：每天100笔，120次投资
    df_all = pd.DataFrame((df.sample(100 * 120)).values,
                          index=list(range(1, 361, 3)) * 100,
                          columns=['price', 'pid', 'timelen'])
    return df_all[df_all.price > 0]  # 去除价格小于0的投资记录


# @GetRunTime
def get_sum(df, n):
    '''
    df:实验数据集
    n:跑路平台数
    result:跑路平台累计坏账金额
    '''
    result = 0
    for i in range(n):  # 一个跑路平台一次实验
        d = random.randint(1, 448)  # 随机日期
        p = random.randint(1, 100)  # 随机平台编号
        result = result + df[
            (df.pid == p) & (df.index < d) & (
                df.index + df.timelen > d)].price.sum()  # 累计坏账金额
    return result


@GetRunTime
def all_test(PP, n=1):
    df_fail = pd.DataFrame(columns=['P', 'Sum', 'Times'])
    for i0 in range(n):  # 实验次数循环
        if i0 % (n / 10.0) == 0:
            print(('test %s is running....' % i0))
        for i1 in pp:  # 分布计算
            PPP = PP[PP.P == i1]
            t_PN = 0
            # 计算平台坏账期望值
            for i2 in range(1, len(PPP)):
                t_PN = get_sum(df_al, i2) * PPP.iloc[i2, :].p + t_PN
            # 记录实验结果
            df_fail = df_fail.append(
                {'P': PPP.iloc[i2, :].P, 'Sum': t_PN, 'Times': i0},
                ignore_index=True)
    return df_fail


def get_pp(pp):
    '''
    计算坏账平台数分布
    '''
    PP = pd.DataFrame(columns=['P', 'N', 'p'])  # 行业跑路率,跑路平台数,概率
    for i in pp:
        ptotal = 0
        for j in range(20):
            p = binom.pmf(j, 100, i)  # 也可以用泊松分布，结果类似
            PP = PP.append({'P': i, 'N': j, 'p': p}, ignore_index=True)
            ptotal = ptotal + p
            if ptotal >= 0.995:  # 累计概率>0.995
                break
    return PP


def plot_df(data):
    '''
    绘制损失金额图形
    '''
    df_al['daySum'] = df_al['price'] * df_al['timelen'] #元/天单位
    totalinvest = int(df_al.daySum.sum() / 360)  # 年投资额

    #ST = scs.describe(data)  # 描述统计量
    NT = scs.norm.fit(data)  # 正态检验

    nn, bins, patches = plt.hist(data, 50, normed=1, facecolor='blue',
                                 alpha=1)  ##绘制损失金额频率分布直方图
    y = mlab.normpdf(bins, NT[0], NT[1])
    plt.plot(bins, y, 'r--', linewidth=1)
    plt.xlabel('Bad Investment')
    plt.ylabel('Freq')
    plt.title(r'$TotalInv=%d , \mu=%d ,\sigma=%d ,i=%.2f $ ' % (
        totalinvest, int(NT[0]), int(NT[1]), round(NT[0] *100/ totalinvest,2)))
    plt.grid(True)
    plt.savefig('DataHist.png')  # 保存直方图
    plt.show()  # 显示直方图
    return NT[0]


if __name__ == '__main__':
    u1 = 5000  # 投资金额均值
    v1 = 15000  # 投资金额标准差
    u2 = 50  # 排名最高的平台编号
    v2 = 9.6  # 平台频率分布直方图的方差
    n = 10000  # 实验次数
    # 生成实验用的投资数据
    df_al = get_df_all()
    # 保存实验投资数据
    df_al.to_csv('df_all.csv',index_label='days')

    # pp = [0.015,0.02,0.025,0.03,0.035,0.04,0.045,0.05]
    pp = [0.02]  # 行业跑路率
    PP = get_pp(pp)  # 坏账平台数分布
    PP.to_csv('pp%s.csv' % pp[0], encoding='utf-8')
    # 对实验投资数据模拟实验n次坏账实验
    p1 = all_test(PP, n)
    # 保存损失金额数据
    p1.to_csv('ps%s.csv' % pp[0], encoding='utf-8')
    # 画出坏账金额

    #df_al=pd.read_csv('df_all.csv')
    #p1=pd.read_csv('ps0.02.csv')

    plot_df(p1.Sum)
    ##程序结束